# -*- coding: utf-8 -*-
# !/usr/bin/env python
import random
import subprocess,os
import threading
import socket,sys
import time

DEBUG = True

try:
    import Tkinter as tk
    import ttk
    from PIL import Image,ImageTk,ImageDraw
except:
    print 'Following module is needed:'
    print '- Tkinter: sudo apt-get install python-tk'
    print '- PIL: sudo apt-get install python-imaging-tk'
    sys.exit()

PATH = lambda p: os.path.abspath(p)
class fb:
    fb_bpp = 0
    fb_size = 0
    fb_width = 0
    fb_height = 0
    red_offset = 0
    red_length = 0
    blue_offset = 0
    blue_length = 0
    green_offset = 0
    green_length = 0
    alpha_offset = 0
    alpha_length = 0
    fb_data = None

    def __init__(self):
        fb_bpp = 0
        fb_size = 0
        fb_width = 0
        fb_height = 0
        red_offset = 0
        red_length = 0
        blue_offset = 0
        blue_length = 0
        green_offset = 0
        green_length = 0
        alpha_offset = 0
        alpha_length = 0
        fb_data = None

# Convert buffer to Int
def getInt(tbuf = None):
    if (tbuf != None):
        if DEBUG:
            hexdump(bytearray(tbuf))
        if len(tbuf) < 4:
            print 'buff len < 4'
            return 0
        else:
            if DEBUG:
                print 'parse: %02x %02x %02x %02x' % (tbuf[0],tbuf[1],tbuf[2],tbuf[3])
            intnum = tbuf[0]
            intnum = intnum + tbuf[1]*0x100
            intnum = intnum + tbuf[2]*0x10000
            intnum = intnum + tbuf[3]*0x1000000
            if DEBUG:
                print 'INT: %08x' % intnum
            return intnum
    else:
        return 0
# Parse fb header from buffer
def readHeader(tfb, ver, buf):
    if DEBUG:
        print 'readHeader: ver = %d' % ver
    if ver == 16:
        tfb.fb_bpp = 16
        tfb.fb_size = getInt(buf[0:4])
        tfb.fb_width = getInt(buf[4:8])
        tfb.fb_height = getInt(buf[8:12])
        tfb.red_offset = 11
        tfb.red_length = 5
        tfb.blue_offset = 5
        tfb.blue_length = 6
        tfb.green_offset = 0
        tfb.green_length = 5
        tfb.alpha_offset = 0
        tfb.alpha_length = 0
    elif ver == 1:
        tfb.fb_bpp = getInt(bytearray(buf[0:4]))
        tfb.fb_size = getInt(bytearray(buf[4:8]))
        tfb.fb_width = getInt(bytearray(buf[8:12]))
        tfb.fb_height = getInt(bytearray(buf[12:16]))
        tfb.red_offset = getInt(bytearray(buf[16:20]))
        tfb.red_length = getInt(bytearray(buf[20:24]))
        tfb.blue_offset = getInt(bytearray(buf[24:28]))
        tfb.blue_length = getInt(bytearray(buf[28:32]))
        tfb.green_offset = getInt(bytearray(buf[32:36]))
        tfb.green_length = getInt(bytearray(buf[36:40]))
        tfb.alpha_offset = getInt(bytearray(buf[40:44]))
        tfb.alpha_length = getInt(bytearray(buf[44:48]))
    else:
        return False
    return True
# Read adb response, if 'OKAY' turn true
def readAdbResponse(s):
    if s != None:
        resp = s.recv(4)
        if DEBUG:
            print 'resp: %s' % repr(resp)
        if len(resp) != 4:
            print 'protocol fault (no status)'
            return False

        if resp == 'OKAY':
            return True
        elif resp == 'FAIL':
            resp = s.recv(4)
            if len(resp) < 4:
                print 'protocol fault (status len)'
                return False
            else:
                length = int(resp, 16)
                resp = s.recv(length)
                if len(resp) != length:
                    print 'protocol fault (status read)'
                    return False
                else:
                    print resp
                    return False
        else:
            print "protocol fault (status %02x %02x %02x %02x?!)", (resp[0], resp[1], resp[2], resp[3])
            return False

        return False
# Print Hex Buffer
def hexdump(buf = None):
    if buf != None:
        pstr = ''
        cnt = 0
        for x in buf:
            if (cnt + 1) % 8 == 0:
                pstr = '%s%02X\n' % (pstr, x)
            else:
                pstr = '%s%02X ' % (pstr, x)
            cnt = cnt + 1
        print pstr

def printD(str):
    if DEBUG:
        print str
    pass
'''
##not work
def getSreenShoot(adbdev):
    path = PATH(os.getcwd() + "/screenshot")
    timestamp = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
    cmd_line = "adb wait-for-device"
    adbdev.cmd(cmd_line)
    cmd_line = "adb shell screencap -p /data/local/tmp/tmp.png"
    adbdev.cmd(cmd_line)
    if not os.path.isdir(PATH(os.getcwd() + "/screenshot")):
        os.makedirs(path)
    cmd_line = "adb pull /data/local/tmp/tmp.png " + PATH(path + "/" + timestamp + ".png")
    adbdev.cmd(cmd_line)
    cmd_line = "adb shell rm /data/local/tmp/tmp.png"
    adbdev.cmd(cmd_line)
'''
class CommonAction:
    __img_factor = 1.00 # image resize rate
    __lcd = None # the label widget
    __keepupdate = True
    __im = None
    __rotate = 0

    def __init__(self):
        pass
    # screen capture via socket from adb server
    def updatelcd_sock(self):
        path = PATH(os.getcwd() + "/screenshot")
        if not os.path.isdir(PATH(os.getcwd() + "/screenshot")):
            os.makedirs(path)
        # make default image display on label
        image = Image.new(mode = 'RGB', size = (640, 720), color = '#000000')
        draw = ImageDraw.Draw(image)
        draw.text((80, 100), 'Connecting...')
        dev_sn = ""
        # Max display area size on label widget
        #max_lcd_w = 1024
        #max_lcd_h = 600
        max_lcd_w = 1440
        max_lcd_h = 720
        hdrsize = 0
        myfb = fb()
        refresh_count = 0 # record refresh count

        while self.__keepupdate:
            # Get device SerialNumber from ADB server
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                s.connect(('127.0.0.1', 5037))
            except:
                os.system('adb start-server')
                time.sleep(2)
                continue

            req_msg = 'host:devices'
            s.sendall('%04x' % len(req_msg))
            s.sendall(req_msg)
            if readAdbResponse(s):
                len_str = s.recv(4)
                if len(len_str) < 4:
                    continue
                length = int(len_str, 16)
                dev_info = s.recv(length)
                if '\t' in dev_info:
                    dev_sn = dev_info[0:dev_info.index('\t')]
                else:
                    dev_sn = ''
                if DEBUG:
                    print 'dev serial: %s' % dev_sn
            s.recv(1024) # receive all rest data
            s.close()

            if dev_sn == '':
                continue
            # Get framebuffer from ADB server
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect(('127.0.0.1', 5037))
            req_msg = 'host:transport:%s' % dev_sn
            s.sendall('%04x' % len(req_msg))
            s.sendall(req_msg)
            if not readAdbResponse(s):
                s.close()
            else:
                if DEBUG:
                    print 'ready to transport'
                req_msg = 'framebuffer:'
                s.sendall('%04x' % len(req_msg))
                s.sendall(req_msg)
                if not readAdbResponse(s):
                    s.close()
                else:
                    reply = s.recv(4)
                    if len(reply) < 4:
                        continue
                    fbver = ord(reply[0]) + \
                            ord(reply[1]) * 0x100 + \
                            ord(reply[2]) * 0x10000 + \
                            ord(reply[3]) * 0x1000000
                    if DEBUG:
                        print 'fbver: %08x' % fbver

                    # Get fb header size
                    if fbver == 16:
                        hdrsize = 3
                    elif fbver == 1:
                        hdrsize = 12
                    else:
                        hdrsize = 0;
                    if DEBUG:
                        print 'fb header size: %d' % hdrsize
                    # read the header
                    header = s.recv(hdrsize * 4)
                    if len(header) < (hdrsize * 4):
                        continue

                    if DEBUG:
                        hexdump(bytearray(header))
                    readHeader(myfb, fbver, header)
                    if DEBUG:
                        print 'bpp: %d' % myfb.fb_bpp
                        print 'size: %d' % myfb.fb_size
                        print 'width: %d' % myfb.fb_width
                        print 'height: %d' % myfb.fb_height
                        print 'red_offset: %d' % myfb.red_offset
                        print 'red_length: %d' % myfb.red_length
                        print 'blue_offset: %d' % myfb.blue_offset
                        print 'blue_length: %d' % myfb.blue_length
                        print 'green_offset: %d' % myfb.green_offset
                        print 'green_length: %d' % myfb.green_length
                        print 'alpha_offset: %d' % myfb.alpha_offset
                        print 'alpha_length: %d' % myfb.alpha_length

                    # read fb buffer
                    rcvcnt = 0
                    readbyte = 0
                    imagebuff = []
                    while True:
                        if (rcvcnt < myfb.fb_size):
                            readbyte = myfb.fb_size - rcvcnt
                        else:
                            break
                        resp = s.recv(readbyte)
                        if DEBUG:
                            print 'read byte: %d' % len(resp)
                        rcvcnt = rcvcnt + len(resp);
                        imagebuff.extend(resp)
                        if len(resp) == 0:
                            break

                    if DEBUG:
                        print 'total rcv byte: %d' % rcvcnt
                    reply = s.recv(10)
                    s.close()
                    myfb.fb_data = bytearray(imagebuff)

                    if len(imagebuff) < myfb.fb_size:
                        continue

                    # convert raw-rgb to image
                    image = Image.frombuffer('RGBA',
                                             (myfb.fb_width, myfb.fb_height),
                                             myfb.fb_data,
                                             'raw',
                                             'RGBA',
                                             0,
                                             1)

                    lcd_w = image.size[0]
                    lcd_h = image.size[1]
                    if DEBUG:
                        print 'LCD size: %d x %d' % (lcd_w,lcd_h)
                    factor_w = 1.00
                    factor_h = 1.00
                    if lcd_w > max_lcd_w:
                        img_w = max_lcd_w
                        factor_w = float(img_w)/float(lcd_w)
                    if lcd_h > max_lcd_h:
                        img_h = max_lcd_h
                        factor_h = float(img_h)/float(lcd_h)
                    factor = min([factor_w, factor_h])
                    self.__img_factor = factor

                    # Keep the rate of w:h
                    img_w = int(lcd_w * factor)
                    img_h = int(lcd_h * factor)

                    # resize image
                    if (factor < 1.00):
                        image = image.resize((img_w, img_h))

                    # rotate image
                    if self.__rotate != 0:
                        image = image.rotate(self.__rotate)

                    refresh_count = refresh_count + 1
                    timestamp = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
                    image_name = PATH(path + "/" + timestamp + 'image_%d.png' % refresh_count)
                    image.save(image_name, format='PNG')

